﻿/*
 * protocolslaver.cpp
 *
 *  Created on: 2017年3月17日
 *      Author: work
 */

#include <dm/export.hpp>

#define DM_API_OS_PROTOCOL DM_API_EXPORT

#include <dm/os/protocol/protocolslaver.hpp>
#include <dm/os/log/logger.hpp>

namespace dm{
namespace os{
namespace protocol{

static const char* logModule = "CProtocolSlaver.protocol.os.dm";

CProtocolSlaver::CProtocolSlaver():CProtocolBase(),m_logicDevice(NULL){
	log().debug(THISMODULE "创建对象");
}

CProtocolSlaver::~CProtocolSlaver(){
	if( m_logicDevice )
		delete m_logicDevice;
	log().debug(THISMODULE "销毁对象");
}

bool CProtocolSlaver::setLogicDeviceById( const dm::scada::id_t& id ){
	if( m_logicDevice==NULL )
		m_logicDevice = new dm::scada::CLogicDevice;

	return m_logicDevice->initById(id);
}

bool CProtocolSlaver::setLogicDeviceByName( const char* name ){
	if( m_logicDevice==NULL )
		m_logicDevice = new dm::scada::CLogicDevice;

	return m_logicDevice->initByName(name);
}

CProtocolSlaver::EAction CProtocolSlaver::taskStart_call( const ts_t& /*ts*/,const rts_t& /*rts*/ ){
	/*
	 * 典型的从站是发送广播消息，通知其他进程更新数据
	 */
	dm::os::msg::CMsgInfo msg;
	msg.setRequest_call(m_callGroup,m_ackCall);
	m_msgAgent.sendMsg(msg);

	m_taskCall = Started;
	return Action_Nothing;
}

CProtocolSlaver::EAction CProtocolSlaver::taskStart_syncClock( const ts_t& /*ts*/,const rts_t& /*rts*/ ){
	dm::os::msg::CMsgInfo msg;
	msg.setRequest_syncClock(m_ackClock);
	m_msgAgent.sendMsg(msg);

	m_taskClock = Started;
	return Action_Nothing;
}

CProtocolSlaver::EAction CProtocolSlaver::taskStart_remoteControl( const ts_t& /*ts*/,const rts_t& /*rts*/ ){
	dm::os::msg::CMsgInfo msg;

	if( m_logicDevice )
		msg.setRequest_remoteCtl( m_logicDevice->physicalRemoteCtl(m_rmtctlIndex),m_rmtctl,m_ackRmtCtl);
	else
		msg.setRequest_remoteCtl( m_rmtctlIndex,m_rmtctl,m_ackRmtCtl);

	m_msgAgent.sendMsg(msg);

	m_taskRmtCtl = Started;
	return Action_Nothing;
}

CProtocolSlaver::EAction CProtocolSlaver::taskStart_parameters( const ts_t& /*ts*/,const rts_t& /*rts*/ ){
	dm::os::msg::CMsgInfo msg;
	if( m_paraSet ){
		if( m_logicDevice )
			msg.setRequest_set( m_logicDevice->physicalParameter(m_paraData.index),m_paraData.num,m_ackParas);
		else
			msg.setRequest_set(m_paraData.index,m_paraData.num,m_ackParas);
		msg.getParaData() = m_paraData;
	}else{
		if( m_logicDevice )
			msg.setRequest_get( m_logicDevice->physicalParameter(m_paraData.index),m_paraData.num,m_ackParas);
		else
			msg.setRequest_get(m_paraData.index,m_paraData.num,m_ackParas);
	}

	m_msgAgent.sendMsg(msg);

	m_taskParas = Started;
	return Action_Nothing;
}

CProtocolSlaver::EAction CProtocolSlaver::taskStart_syncData( const ts_t& /*ts*/,const rts_t& /*rts*/ ){
	dm::os::msg::CMsgInfo msg;
	msg.setRequest_sync(m_syncType,m_ackSync);

	m_msgAgent.sendMsg(msg);

	m_taskSync = Started;
	return Action_Nothing;
}

CProtocolSlaver::EAction CProtocolSlaver::taskStart_reset( const ts_t& /*ts*/,const rts_t& /*rts*/ ){
	dm::os::msg::CMsgInfo msg;
	msg.setRequest_remoteReset(m_ackReset);

	m_msgAgent.sendMsg(msg);

	m_taskReset = Started;
	return Action_Nothing;
}

CProtocolSlaver::EAction CProtocolSlaver::taskDo_call( const ts_t& /*ts*/,const rts_t& /*rts*/ ){
	if( m_ackCall )
		return Action_ReTime;
	else
		m_taskCall = Success;

	return Action_Nothing;
}

CProtocolSlaver::EAction CProtocolSlaver::taskDo_syncClock( const ts_t& /*ts*/,const rts_t& /*rts*/ ){
	if( m_ackClock )
		return Action_ReTime;
	else
		m_taskClock = Success;

	return Action_Nothing;
}

CProtocolSlaver::EAction CProtocolSlaver::taskDo_remoteControl( const ts_t& /*ts*/,const rts_t& /*rts*/ ){
	if( m_ackRmtCtl )
		return Action_ReTime;
	else
		m_taskRmtCtl = Success;

	return Action_Nothing;
}

CProtocolSlaver::EAction CProtocolSlaver::taskDo_parameters( const ts_t& /*ts*/,const rts_t& /*rts*/ ){
	if( m_ackParas )
		return Action_ReTime;
	else
		m_taskParas = Success;

	return Action_Nothing;
}

CProtocolSlaver::EAction CProtocolSlaver::taskDo_syncData( const ts_t& /*ts*/,const rts_t& /*rts*/ ){
	if( m_ackSync )
		return Action_ReTime;
	else
		m_taskSync = Success;

	return Action_Nothing;
}

CProtocolSlaver::EAction CProtocolSlaver::taskDo_reset( const ts_t& /*ts*/,const rts_t& /*rts*/ ){
	if( m_ackReset ){
		return Action_ReTime;
	}else
		m_taskReset = Success;

	return Action_Nothing;
}

/**
 * 获取状态量个数
 * 如果设置了逻辑设备，则使用逻辑设备配置。否则使用系统全数据。
 * @return
 */
int CProtocolSlaver::statusSize()const{
		return m_logicDevice?m_logicDevice->statusSize():dm::scada::CStatusMgr::ins().size();
}

int CProtocolSlaver::discreteSize()const{
	return m_logicDevice?m_logicDevice->discreteSize():dm::scada::CDiscreteMgr::ins().size();
}

int CProtocolSlaver::measureSize()const{
	return m_logicDevice?m_logicDevice->measureSize():dm::scada::CMeasureMgr::ins().size();
}

int CProtocolSlaver::cumulantSize()const{
	return m_logicDevice?m_logicDevice->cumulantSize():dm::scada::CCumulantMgr::ins().size();
}

int CProtocolSlaver::remoteControlSize()const{
	return m_logicDevice?m_logicDevice->remoteCtlSize():dm::scada::CRemoteCtlMgr::ins().size();
}

int CProtocolSlaver::parameterSize()const{
	return m_logicDevice?m_logicDevice->parameterSize():dm::scada::CParameterMgr::ins().size();
}

int CProtocolSlaver::actionSize()const{
	return m_logicDevice?m_logicDevice->actionSize():dm::scada::CActionMgr::ins().size();
}

const CProtocolSlaver::status_rt_t* CProtocolSlaver::statusRt( const index_t& idx )const{
	return m_logicDevice?m_logicDevice->status(idx):dm::scada::CStatusMgr::ins().rt(idx);
}

const CProtocolSlaver::discrete_rt_t* CProtocolSlaver::discreteRt( const index_t& idx )const{
	return m_logicDevice?m_logicDevice->discrete(idx):dm::scada::CDiscreteMgr::ins().rt(idx);
}

const CProtocolSlaver::measure_rt_t* CProtocolSlaver::measureRt( const index_t& idx )const{
	return m_logicDevice?m_logicDevice->measure(idx):dm::scada::CMeasureMgr::ins().rt(idx);
}

const CProtocolSlaver::cumulant_rt_t* CProtocolSlaver::cumulantRt( const index_t& idx )const{
	return m_logicDevice?m_logicDevice->cumulant(idx):dm::scada::CCumulantMgr::ins().rt(idx);
}

CProtocolSlaver::index_t CProtocolSlaver::statusIndex( const index_t& hostIdx )const{
	return m_logicDevice?m_logicDevice->logicalStatus(hostIdx):hostIdx;
}

CProtocolSlaver::index_t CProtocolSlaver::discreteIndex( const index_t& hostIdx )const{
	return m_logicDevice?m_logicDevice->logicalDiscrete(hostIdx):hostIdx;
}

CProtocolSlaver::index_t CProtocolSlaver::measureIndex( const index_t& hostIdx )const{
	return m_logicDevice?m_logicDevice->logicalMeasure(hostIdx):hostIdx;
}

CProtocolSlaver::index_t CProtocolSlaver::cumulantIndex( const index_t& hostIdx )const{
	return m_logicDevice?m_logicDevice->logicalCumulant(hostIdx):hostIdx;
}

CProtocolSlaver::index_t CProtocolSlaver::remoteControlIndex( const index_t& hostIdx )const{
	return m_logicDevice?m_logicDevice->logicalRemoteCtl(hostIdx):hostIdx;
}

CProtocolSlaver::index_t CProtocolSlaver::parameterIndex( const index_t& hostIdx )const{
	return m_logicDevice?m_logicDevice->logicalParameter(hostIdx):hostIdx;
}

CProtocolSlaver::index_t CProtocolSlaver::actionIndex( const index_t& hostIdx )const{
	return m_logicDevice?m_logicDevice->logicalAction(hostIdx):hostIdx;
}

CProtocolSlaver::index_t CProtocolSlaver::getHostStatusIndex( const index_t& idx )const{
	return m_logicDevice?m_logicDevice->physicalStatus(idx):idx;
}



CProtocolSlaver::index_t CProtocolSlaver::getHostDiscreteIndex( const index_t& idx )const{
	return m_logicDevice?m_logicDevice->physicalDiscrete(idx):idx;
}

CProtocolSlaver::index_t CProtocolSlaver::getHostMeasureIndex( const index_t& idx )const{
	return m_logicDevice?m_logicDevice->physicalMeasure(idx):idx;
}

CProtocolSlaver::index_t CProtocolSlaver::getHostCumulantIndex( const index_t& idx )const{
	return m_logicDevice?m_logicDevice->physicalCumulant(idx):idx;
}

CProtocolSlaver::index_t CProtocolSlaver::getHostRemoteControlIndex( const index_t& idx )const{
	return m_logicDevice?m_logicDevice->physicalRemoteCtl(idx):idx;
}

CProtocolSlaver::index_t CProtocolSlaver::getHostParameterIndex( const index_t& idx )const{
	return m_logicDevice?m_logicDevice->physicalParameter(idx):idx;
}

CProtocolSlaver::index_t CProtocolSlaver::getHostActionIndex( const index_t& idx )const{
	return m_logicDevice?m_logicDevice->physicalAction(idx):idx;
}

CProtocolSlaver::ETaskState CProtocolSlaver::ack2taskState( const dm::msg::EMsgAck& ack ){
	switch( ack ){
	case dm::msg::MaSuccess:
	case dm::msg::MaPart:
		return Success;

	case dm::msg::MaTimeout:
		return Timeout;

	case dm::msg::MaDeny:
	case dm::msg::MaBusy:
		return Permit;

	case dm::msg::MaFail:
	case dm::msg::MaParas:
	case dm::msg::MaIndex:
	default:
		return Fail;
	}
}

bool CProtocolSlaver::filterMsgRequest_syncClock( const dm::os::msg::CMsgInfo&){
	return true;
}

bool CProtocolSlaver::filterMsgRequest_call( const dm::os::msg::CMsgInfo&){
	return true;
}

bool CProtocolSlaver::filterMsgRequest_rmtCtl( const dm::os::msg::CMsgInfo& ){
	return true;
}

bool CProtocolSlaver::filterMsgRequest_set( const dm::os::msg::CMsgInfo& ){
	return true;
}

bool CProtocolSlaver::filterMsgRequest_get( const dm::os::msg::CMsgInfo& ){
	return true;
}

bool CProtocolSlaver::filterMsgRequest_update( const dm::os::msg::CMsgInfo& msg){
	return parameterIndex(msg.getParaData().index)<0;
}

bool CProtocolSlaver::filterMsgRequest_syncData( const dm::os::msg::CMsgInfo& ){
	return true;
}

bool CProtocolSlaver::filterMsgRequest_remoteReset( const dm::os::msg::CMsgInfo& ){
	return true;
}

bool CProtocolSlaver::filterMsgAnswer_syncClock( const dm::os::msg::CMsgInfo& ){
	return false;
}

bool CProtocolSlaver::filterMsgAnswer_call( const dm::os::msg::CMsgInfo& ){
	return false;
}

bool CProtocolSlaver::filterMsgAnswer_rmtCtl( const dm::os::msg::CMsgInfo& msg){
	return remoteControlIndex(msg.getRemoteCtl().index)<0;
}

bool CProtocolSlaver::filterMsgAnswer_set( const dm::os::msg::CMsgInfo& msg){
	return parameterIndex(msg.getPara().index)<0;
}

bool CProtocolSlaver::filterMsgAnswer_get( const dm::os::msg::CMsgInfo& msg){
	return parameterIndex(msg.getParaData().index)<0;
}

bool CProtocolSlaver::filterMsgAnswer_update( const dm::os::msg::CMsgInfo& ){
	return true;
}

bool CProtocolSlaver::filterMsgAnswer_syncData( const dm::os::msg::CMsgInfo& ){
	return true;
}

bool CProtocolSlaver::filterMsgAnswer_remoteReset( const dm::os::msg::CMsgInfo& ){
	return false;
}


CProtocolSlaver::EAction CProtocolSlaver::onMsgRequest_syncClock( dm::os::msg::CMsgInfo& ,const ts_t& /*ts*/,const rts_t& /*rts*/  ){
	return Action_Nothing;
}

CProtocolSlaver::EAction CProtocolSlaver::onMsgRequest_call( dm::os::msg::CMsgInfo& ,const ts_t& /*ts*/,const rts_t& /*rts*/  ){
	return Action_Nothing;
}

CProtocolSlaver::EAction CProtocolSlaver::onMsgRequest_rmtCtl( dm::os::msg::CMsgInfo& ,const ts_t& /*ts*/,const rts_t& /*rts*/  ){
	return Action_Nothing;
}

CProtocolSlaver::EAction CProtocolSlaver::onMsgRequest_set( dm::os::msg::CMsgInfo& ,const ts_t& /*ts*/,const rts_t& /*rts*/  ){
	return Action_Nothing;
}

CProtocolSlaver::EAction CProtocolSlaver::onMsgRequest_get( dm::os::msg::CMsgInfo& ,const ts_t& /*ts*/,const rts_t& /*rts*/  ){
	return Action_Nothing;
}

CProtocolSlaver::EAction CProtocolSlaver::onMsgRequest_update( dm::os::msg::CMsgInfo& ,const ts_t& /*ts*/,const rts_t& /*rts*/ ){
	return Action_Nothing;
}

CProtocolSlaver::EAction CProtocolSlaver::onMsgRequest_syncData( dm::os::msg::CMsgInfo& ,const ts_t& /*ts*/,const rts_t& /*rts*/ ){
	return Action_Nothing;
}

CProtocolSlaver::EAction CProtocolSlaver::onMsgRequest_remoteReset( dm::os::msg::CMsgInfo& ,const ts_t& /*ts*/,const rts_t& /*rts*/ ){
	return Action_Nothing;
}

CProtocolSlaver::EAction CProtocolSlaver::onMsgAnswer_syncClock( dm::os::msg::CMsgInfo& msg,const ts_t& ts,const rts_t& rts ){
	if( m_taskClock==Started && m_ackClock ){
		m_taskClock = ack2taskState(msg.getAck());
		return taskEnd_syncClock(ts,rts);
	}

	return Action_Nothing;
}

CProtocolSlaver::EAction CProtocolSlaver::onMsgAnswer_call( dm::os::msg::CMsgInfo& msg,const ts_t& ts,const rts_t& rts ){
	if( m_taskCall==Started && m_ackCall && m_callGroup==msg.getCall().group ){
		m_taskCall = ack2taskState(msg.getAck());
		return taskEnd_call(ts,rts);
	}

	return Action_Nothing;
}

CProtocolSlaver::EAction CProtocolSlaver::onMsgAnswer_rmtCtl( dm::os::msg::CMsgInfo& msg,const ts_t& ts,const rts_t& rts ){
	if( m_taskRmtCtl==Started && m_ackRmtCtl && m_rmtctl==msg.getRemoteCtl().remoteCtl ){
		if( (m_logicDevice && m_logicDevice->physicalRemoteCtl(m_rmtctlIndex)==msg.getRemoteCtl().index)
				|| m_rmtctlIndex==msg.getRemoteCtl().index ){
			m_taskRmtCtl = ack2taskState(msg.getAck());
			return taskEnd_remoteControl(ts,rts);
		}
	}

	return Action_Nothing;
}

CProtocolSlaver::EAction CProtocolSlaver::onMsgAnswer_set( dm::os::msg::CMsgInfo& msg,const ts_t& ts,const rts_t& rts ){
	if( m_taskParas==Started && m_paraSet && m_ackParas ){
		if( (m_logicDevice && m_logicDevice->physicalParameter(m_paraData.index)==msg.getPara().index) ||
				m_paraData.index==msg.getPara().index )
		m_taskParas = ack2taskState(msg.getAck());
		return taskEnd_parameters(ts,rts);
	}

	return Action_Nothing;
}

CProtocolSlaver::EAction CProtocolSlaver::onMsgAnswer_get( dm::os::msg::CMsgInfo& msg,const ts_t& ts,const rts_t& rts ){
	if( m_taskParas==Started && !m_paraSet && m_ackParas &&
			(m_paraData.index==msg.getParaData().index ||(m_logicDevice &&m_logicDevice->physicalParameter(m_paraData.index)==msg.getParaData().index))){
		m_paraData = msg.getParaData();
		m_taskParas = ack2taskState(msg.getAck());

		return taskEnd_parameters(ts,rts);
	}

	return Action_Nothing;
}

CProtocolSlaver::EAction CProtocolSlaver::onMsgAnswer_update( dm::os::msg::CMsgInfo& ,const ts_t& /*ts*/,const rts_t& /*rts*/ ){
	return Action_Nothing;
}

CProtocolSlaver::EAction CProtocolSlaver::onMsgAnswer_syncData( dm::os::msg::CMsgInfo& msg,const ts_t& ts,const rts_t& rts ){
	if( m_taskSync==Started && m_ackSync ){
		m_taskSync = ack2taskState(msg.getAck());
		return taskEnd_syncData(ts,rts);
	}

	return Action_Nothing;
}

CProtocolSlaver::EAction CProtocolSlaver::onMsgAnswer_remoteReset( dm::os::msg::CMsgInfo& msg,const ts_t& ts,const rts_t& rts ){
	if( m_taskReset==Started && m_ackReset ){
		m_taskReset = ack2taskState(msg.getAck());
		return taskEnd_reset(ts,rts);
	}

	return Action_Nothing;
}

}
}
}


